/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_kernel.htm
 *
 * Zhiqim Kernel is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.kernel.model.codes;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CRL;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collection;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.zhiqim.kernel.constants.CodeConstants;
import org.zhiqim.kernel.util.Asserts;

/**
 * SSL相关工具类
 *
 * @version v1.0.0 @author zouzhigang 2014-2-27 新建与整理
 */
public class SSL implements CodeConstants
{
    /** 初始化SSL上下文环境 */
    public static SSLSocketFactory getSocketFactory(String protocol, KeyManager[] keyManager, TrustManager[] trustManager) throws NoSuchAlgorithmException, KeyManagementException
    {
        SSLContext ctx = SSLContext.getInstance(protocol);
        ctx.init(keyManager==null?null:keyManager, trustManager==null?new TrustManager[]{new DefaultTrustManager()}:trustManager, new SecureRandom());

        return ctx.getSocketFactory();
    }
    
    /** 缺省的信任管理器 */
    public static class DefaultTrustManager implements X509TrustManager
    {
        public X509Certificate[] getAcceptedIssuers()
        {
            return null;
        }

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException
        {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException
        {
        }
    }

    /** 缺省的主机验证类 */
    public static class DefaultHostnameVerifier implements HostnameVerifier
    {
        public boolean verify(String hostname, SSLSession session) 
        {
            return true;
        }
    }

    /**
     * 生成证书
     * 
     * @param crtPath                   证书CRT文件路径
     * @return                          证书对象
     * @throws CertificateException     证书异常
     * @throws IOException              IO异常
     */
    public static Certificate generateCertificate(String crtPath) throws CertificateException, IOException
    {
        Asserts.as(crtPath != null?null:"证书CRT文件路径不能为null");

        try (InputStream is = new FileInputStream(crtPath);)
        {
            return CertificateFactory.getInstance(_X_509_).generateCertificate(is);
        }
        
    }
    
    /**
     * 获取KeyStore，指定存储路径、类型、提供者和密码
     * 
     * @param storePath     存储路径
     * @param storeType     存储类型
     * @param storeProvider 提供者
     * @param storePassword 密码
     * @return              KeyStore
     * @throws Exception    捕捉异常
     */
    public static KeyStore getKeyStore(String storePath, String storeType, String storeProvider, String storePassword)throws Exception
    {
        try (InputStream is = new FileInputStream(storePath);)
        {
            return getKeyStore(is, storeType, storeProvider, storePassword);
        }
    }
    
    /**
     * 获取KeyStore，指定流，存储类型、提供者和密码
     * 
     * @param is            
     * @param storeType     存储类型
     * @param storeProvider 提供者
     * @param storePassword 密码
     * @return              KeyStore
     * @throws Exception    捕捉异常
     */
    public static KeyStore getKeyStore(InputStream is, String storeType, String storeProvider, String storePassword) throws Exception
    {
        KeyStore keystore = null;
        if (storeProvider != null)
            keystore = KeyStore.getInstance(storeType, storeProvider);
        else
            keystore = KeyStore.getInstance(storeType);

        keystore.load(is, storePassword == null ? null : storePassword.toCharArray());
        return keystore;
    }

    /**
     * 加载CRL，指定CRL路径
     * 
     * @param crlPath       CRL路径
     * @return              得到CRL列表
     * @throws Exception    捕捉异常
     */
    public static Collection<? extends CRL> loadCRL(String crlPath) throws Exception
    {
        if (crlPath == null)
            return null;
        
        try (InputStream is = new FileInputStream(crlPath))
        {
            return CertificateFactory.getInstance(_X_509_).generateCRLs(is);
        }
    }
}
